<?php


namespace app\cms\model;

use app\cms\community\lib\QueryModel;
use app\cms\dto\bindPhoneOrEmail;
use app\cms\dto\changePassword;
use app\cms\dto\registerForm;
use app\cms\dto\userInfo;
use iflow\facade\Session;
use iflow\Response;
use think\db\exception\DataNotFoundException;
use think\db\exception\DbException;
use think\db\exception\ModelNotFoundException;
use think\Model;

class userModel extends QueryModel
{
    protected $table = 'user_table';

    protected string $logsModelClass = loginLogsModel::class;
    protected loginLogsModel $logsModel;

    public function initialization()
    {
        $this->logsModel = new $this -> logsModelClass;
    }

    /**
     * 账号密码登录
     * @param userInfo $userInfo
     * @return Response
     * @throws \Exception
     */
    public function login(userInfo $userInfo): Response
    {
        $user = $this->where([
            'user_name' => $userInfo -> userName
        ]) -> hidden(['password']) -> findOrEmpty();
        if ($user -> isExists()) {

            // 验证密码
            if (!password_verify($userInfo -> passWord, $user -> getData('password'))) {
                $this->logsModel -> createLogsInfo($user['uid'], $user['user_name'], "登录失败 - 账号或密码错误");
                return message() -> unauthorized_error('密码错误');
            }

            // 验证账户状态
            if ($user -> getData('status') === 2) {
                $this->logsModel -> createLogsInfo($user['uid'], $user['user_name'], "登录失败 - 账号已被封禁");
                return message() -> unauthorized_error('账号已被封禁 请联系管理员解封');
            }

            // 验证账户状态
            if ($user -> getData('status') === 0) {
                return message() -> unauthorized_error('账号未验证，请验证后登录');
            }

            $user = $user -> toArray();

            // 登录域名
            $user['domain'] = request() -> getDomain();
            session('userInfo', $user);
            $user['authorization'] = Session::getSessionId();
            $this->logsModel -> createLogsInfo($user['uid'], $user['user_name'], "登录成功");
            return message() -> success('登录成功', $user);
        }
        return message() -> unauthorized_error('用户名不存在');
    }

    /**
     * 获取单个用户信息
     * @param int $uid
     * @return array|null
     */
    public function getUser(int $uid = 0): array|null
    {
        $user = $this->withJoin([
            'hasUserGroup' => [
                'user_group_name' => 'user_group_name',
                'user_group_parent_id' => 'user_group_parent_id'
            ]
        ], 'LEFT') -> where([
            'uid' => $uid
        ]) -> hidden([
            'password'
        ]) -> findOrEmpty();
        if ($user -> isExists()) {
            return $user -> toArray();
        }
        return null;
    }

    /**
     * 绑定用户组
     * @return \think\model\relation\HasOne
     */
    public function hasUserGroup(): \think\model\relation\HasOne
    {
        return $this->hasOne(userGroupModel::class, 'user_group_id', 'user_group_id');
    }

    /**
     * 获取用户列表
     * @param int $userGroup
     * @param string $userName
     * @return Response
     * @throws DbException
     */
    public function getUserList(int $userGroup = 0, string $userName = ''): Response
    {
        $where = [];
        if ($userGroup > 0) {
            $where[ $this->table. '.user_group_id'] = $userGroup;
        }

        $query = $this->withJoin([
            'hasUserGroup' => [
                'user_group_name' => 'user_group_name',
                'user_group_parent_id' => 'user_group_parent_id'
            ]
        ], 'LEFT')
            -> where($where)
            -> hidden(['password']);

        if ($userName !== '') {
            $query -> whereLike('user_name', "%{$userName}%");
        }
        $query = $query -> paginate([
            'page' => request() -> getParams('page'),
            'list_rows' => 10
        ]);
        $items = $query -> items();

        return $items ?
            message() -> success('查询成功', $items, [
                'count' => $query -> total(),
                'page' => $query -> lastPage()
            ]): message() -> nodata('暂无数据');
    }

    /**
     * 通过角色组id获取单个用户
     * @param int $user_group_id
     * @return array|Model
     */
    public function userByGroup(int $user_group_id): array|Model
    {
        return $this->where([
            'user_group_id' => $user_group_id
        ]) -> findOrEmpty();
    }

    /**
     * (解)封禁指定账户
     * @param int $uid
     * @return Response
     */
    public function changeUserStatus(int $uid): Response
    {
        $user = $this->where([
            'uid' => $uid
        ]) -> findOrEmpty();

        if ($user -> isEmpty()) return message() -> nodata('账户不存在');

        $update = self::update([
            'status' => intval($user['status']) === 2 ? 1 : 2
        ], ['uid' => $uid]) -> toArray();
        return message() -> success('更新成功', $update);
    }

    /**
     * 指定条件获取账户信息
     * @param array $where
     * @return array
     */
    public function getUserInfo(array $where = []): array
    {
        $user = $this->where($where) -> findOrEmpty();
        if ($user -> isEmpty()) return [];
        return $user -> toArray();
    }

    /**
     * 注册账户
     * @param registerForm $registerForm
     * @return Response
     */
    public function createUser(registerForm $registerForm): Response
    {
        $type = $registerForm -> email === '' ? 'phone' : 'email';

        if ($this->getUserInfo([$type => $registerForm -> {$type}])) {
            return message() -> update_failed("$type 已存在");
        }

        if ($this->getUserInfo([
            'user_name' => $registerForm -> userName
        ])) {
            return message() -> update_failed("userName 已存在");
        }

        $sms = (new saveSmsModel()) -> getSmsLine(
            $registerForm -> sms['uuid'],
            $registerForm -> sms['code'],
            $registerForm -> {$type}
        );

        if ($sms -> getError() !== "") return message() -> unauthorized_error($sms -> getError());

        try {
            $this->startTrans();
            $userInfo = $this -> create([
                $type => $registerForm -> {$type},
                'password' => password_hash($registerForm -> passWord, PASSWORD_DEFAULT),
                'user_name' => $registerForm -> userName,
                'user_group_id' => 2,
                'gender' => 2,
                'phone' => microtime(),
                'status' => 1,
                'role' => 'user'
            ]) -> toArray();

            if ($userInfo && ($registerForm -> oauth['openid'] !== '' && $registerForm -> oauth['type'] !== '')) {
                $oauth = $this -> create([
                    'oauth_openid' => $registerForm -> oauth['openid'],
                    'type' => $registerForm -> oauth['type']
                ]) -> toArray();
                $userInfo['oauth'] = $oauth;
            }
            $this->commit();
            return message() -> success('注册成功', $userInfo);
        } catch (\Exception $exception) {
            $this->rollback();
            return message() -> success('注册失败, 请重试'. $exception -> getMessage());
        }
    }

    /**
     * 更改密码
     * @param changePassword $changePassword
     * @return Response
     */
    public function changePassword(changePassword $changePassword): Response
    {
        if ($changePassword -> passWord !== $changePassword -> confirmPassword) {
            return message() -> parameter_error('密码不一致');
        }
        $sms = (new saveSmsModel()) -> getSmsLine(
            $changePassword -> sms['uuid'],
            $changePassword -> sms['code'],
            $changePassword -> account,
        );
        if ($sms -> getError() !== "") return message() -> unauthorized_error($sms -> getError());
        self::update([
            'password' => password_hash($changePassword -> passWord, PASSWORD_DEFAULT)
        ], [
            'uid' => $changePassword -> getUid()
        ]);
        return message() -> success('更新密码成功');
    }

    /**
     * 更改绑定 邮箱/手机
     * @param bindPhoneOrEmail $bindPhoneOrEmail
     * @return Response
     * @throws DataNotFoundException
     * @throws DbException
     * @throws ModelNotFoundException
     */
    public function bindPhoneOrEmail(bindPhoneOrEmail $bindPhoneOrEmail): Response
    {

        $uid = $bindPhoneOrEmail -> getUid();
        $userInfo = $this->where([
            'uid' => $uid
        ]) -> find() -> toArray();

        $type = $bindPhoneOrEmail -> getChangeAccountType();

        if ($type === false) {
            return message() -> parameter_error('新邮箱/手机号格式错误');
        }


        $account = $bindPhoneOrEmail -> account;

        if ($bindPhoneOrEmail -> checkOldAccount($userInfo[$type], $type)) {
            $account = $bindPhoneOrEmail -> oldAccount;
            if ($userInfo[$type] !== $bindPhoneOrEmail -> oldAccount) {
                return message()->parameter_error("原账户${type}不一致");
            }
        }

        $sms = (new saveSmsModel()) -> getSmsLine(
            $bindPhoneOrEmail -> sms['uuid'],
            $bindPhoneOrEmail -> sms['code'],
            $account,
        );
        if ($sms -> getError() !== "") return message() -> unauthorized_error($sms -> getError());

        self::update([
            $type => $bindPhoneOrEmail -> account
        ], [
            'uid' => $uid
        ]);
        return message() -> success("更新 $type 成功");
    }
}